<?php
namespace app\admin\middleware;
use think\facade\Config;
use think\facade\Request;
use think\facade\Cache;
use think\facade\Session;
use think\facade\Cookie;
use Auth\Auth;
use Firebase\JWT;

/**
 * 争个后台模块接口请求处理中间件
 */
class AdminBaseCheck
{
	/**
	 * handle  重写处理请求对象的操作函数
	 * @param  object Request $request 请求对象
	 * @param  object \Closure $next 响应对象
	 * @return array 错误返回的信息
	 *         code 返回码
	 *         msg 返回信息
	 *         data 返回数据
	 * @return  object 响应对象
	 */
	public function handle($request, \Closure $next)
	{
		// 获取控制器信息
		$module = strtolower(Request::module());
		$controller = self::controllerStr(Request::controller());
		$controller1 = strtolower(Request::controller());
		$function = strtolower(Request::action());
		// 对请求接口目标路径进行处理如果带有扩展名则将扩展名消除
		if (preg_match("/^[\w][\w]{0,31}[\.][a-zA-Z]{1,10}$/", $function)) $function = explode('.',$function)[0];
		else $function = $function;
		// 如果是登录接口则略过 否则除了登录接口外 全部均使用这个检测
		if ($controller === 'login') return $next($request);
		$config = Config::get($controller1.'.');
		// 如果oauth2授权是开启的 则进行授权认证
		if (true === Config::get('web.oauth2'))
		{
			$res = self::oauthCheck($request);
			if (is_string($res)) exit(json_encode(['code'=>1,'msg'=>$res,'data'=>'']));
		}
		// 如果auth权限验证是开启的，则进行权限验证
		if (true === Config::get('web.auth'))
		{
			$res = self::authCheck($request,$controller,$function);
			if (true !== $res) exit(json_encode(['code'=>1,'msg'=>'Not_Auth_Power','data'=>'']));
		}
		// 对页面 访问进行检测
		if (true === $config['page'])
		{
			$res = self::pageCheck($function,$config['page_switch']);
			if (true !== $res) exit(json_encode(['code'=>1,'msg'=>'Page_Disable','data'=>'']) );
		}
		// 对api 访问进行检测
		if (true === $config['api'])
		{
			$res = self::apiCheck($function,$config['api_switch']);
			if (true !== $res) exit(json_encode(['code'=>1,'msg'=>'Api_Disable','data'=>'']) );
		}
		if (true === Config::get('web.repeat_token'))
		{
			$res = self::tokenCheck();
			if (true !== $res) exit(json_encode(['code'=>1,'msg'=>'Token_Data_Failure','data'=>'']));
		}
		// 传入相应的请求件
		return $next($request);
	}

	/**
	 * controllerStr description
	 * @param  [type] $controller [description]
	 * @return [type]             [description]
	 */
	protected static function controllerStr($controller)
	{
		// 将控制器大小写拆分成下划线形式 每增加一个控制器这里都需要增加一个对应数据转换
		$array = 
		[
			'AdminGroup'=>'admin_group',
			'AdminRules'=>'admin_rules',
			'AdminUser'=>'admin_user',
			'Login'=>'Login',
		];
		// 
		@$str = $array[$controller];
		if (empty($str)) return strtolower($controller);
		else return $str;
	}

	/**
	 * oauthCheck 对于oauth的检测
	 * @param  object $request 请求对象
	 * @return object 返回请求对象
	 */
	protected static function oauthCheck($request)
	{
		try
		{
			// 获取用户Oauth2配置
			$config = Config::get('web.oauth_config');
			//接收Token信息
			$header_token = $request->header('Authorization');
			// 如果Token为空的时候 返回信息
			if (empty($header_token)) return 'Token_Not_Empty';
			// Token解码 时间过期的时候 返回错误信息
			$decode = JWT::decode($header_token, $config['token_key'],['HS256']);
			if ($decode->exp < time()) return 'Token_Time_Overdue';
			// 读取缓存信息是否存在不存在返回错误
			$admin = Cache::tag(Config::get('admin.user.tag'))->get($decode->aud);
			if (false === $admin) return 'Admin_Not_Existent';
			// 返回请求对象
			$request->$admin = $admin;
			return $request;
		} catch (\Exception $e) {
			$str = $e->getMessage();
			return $str;
		}
	}

	/**
	 * authCheck description
	 * @param  [type] $request [description]
	 * @param  [type] $c       [description]
	 * @param  [type] $f       [description]
	 * @return [type]          [description]
	 */
	public static function authCheck($request,$c,$f)
	{
		$config = Config::get('admin.user');
		// 如果关闭oauth的情况
		if (false === Config::get('web.oauth2'))
		{
			// 利用session作为用户存储
			$user = Cache::tag($config['tag'])->get(session_id());
			$auth = new Auth();
			// 验证用户权限
			$str = $c.'/'.$f;
			dump($c);
			$res = $auth->check($str,$user['id']);
			if (false  === $res) return false;
			else return true;
		}
		else
		{
			// 开启oauth之后 利用用户id进行存储
			$admin = $request->param('admin');
			$user = Cache::tag($config['tag'])->get($user['id']);
			$auth = new Auth();
			$res = $auth ->check($c.'/'.$f,$user['id']);
			if (false  === $res) return false;
			else return true;
			return true;
		}
	}

	protected static function pageCheck($scene,$config)
	{
		// 场景判断
		switch ($scene)
		{
			case $scene:
				// 键是否存在于配置中
				$page = key_exists($scene,$config);
				// 如果键存在则取出数据 否则返回
				if (true === $page) $switch = $config[$scene];
				else {$res = '2';break;}
				// 页面打开或者关闭的状态
				if (true === $switch) {$res = '0';break;}
				else {$res = '1';break;}
		}
		// 结果反馈
		switch ($res)
		{
			case '0': return true; break;// 页面开启状态
			case '1': return false; break;// 页面关闭状态
			case '2': return true; break;// 页面不存在状态 不做任何处理 可能需要指向404更好
		}
	}

	protected static function apiCheck($scene,$config)
	{
		// 场景判断
		switch ($scene)
		{
			case $scene:
				// 键是否存在于配置中
				$api = key_exists($scene,$config);
				// 如果键存在则取出数据 否则返回
				if (true === $api) $switch = $config[$scene];
				else {$res = '2';break;}
				// api打开或者关闭的状态
				if (true === $switch) {$res = '0';break;}
				else {$res = '1';break;}
		}
		// 结果反馈
		switch ($res)
		{
			case '0': return true; break;// Api开启状态
			case '1': return false; break;// Api关闭状态
			case '2': return true; break;// Api不存在状态 
		}
	}

	/**
	 * 这段要着重处理的内容  整个中间件处理完成之后,就可以 写信的代码了
	 * 表单方重复提交令牌
	 * @return bool           返回真假值
	 */
	protected static function tokenCheck()
	{
		// 获取配置参数
		$config = Config::get('web.repeat_token_config');
		// 自设函数
		$tokenCheck_on = function ($config)
		{
			// 产生微秒时间戳
			if (true === $config['microtime']) $token['time'] = microtime();
			// 产生随机数
			if (true === $config['rand']) $token['rand'] = mt_rand(100000,999999);
			// 获取加密钥匙
			$token['key'] =  $config['key'];
			// 获取提交的内容参数
			$token['param'] = json_encode(Request::param());
			// 设置合并参数变量
			$merge = '';
			// 循环加密内容
			foreach ($token as $key => $val) { $merge .= $val; }
			// 数据加密
			$data = md5($merge);
			// 存储密文信息到cookie 等待读取
			Cookie::set($config['tag'],$data,$config['time']);
			// 设置缓存标
			Cache::tag($config['tag'])->set($data,$token,$config['time']);
			// 获取cookie中的token数据
			return $token;
		};

		// 自解函数
		$tokenCheck_de = function ($token,$config)
		{
			// 获取id
			$id = Cookie::get($config['tag']);
			// 获取缓存数据
			$data = Cache::tag($config['tag'])->get($id);
			// 设置验证参数变量
			$verify = '';
			// 循环cookie内容
			foreach ($data as $key => $val) $verify .= $val;
			// md5解密验证
			$verify = md5($verify);
			// 如果单次传入相等则通过
			if ($id === $verify) return true;
			else return false;
		};
		$token = $tokenCheck_on($config);
		$res = $tokenCheck_de($token,$config);
		return $res;
	}
}
